package monitor

import (
	"gitee.com/amoyx/cloud-provider/pkg/cloud/tencent/models"
	tapm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/apm/v20210622"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	"strings"
)

type ApmGreeter interface {
	APM(region string) ApmInterface
}

type ApmInterface interface {
	Get(id string) (result models.ApmResponse, err error)
	Create(args models.ApmRequest) (result models.CreateResponseParams, err error)
	ListByName(name string) (list []models.ApmResponse, err error)
	ListAll() (list []models.ApmResponse, err error)
	DescribeApmAgent(args models.ApmAgentRequest) (result models.ApmAgentInfo, err error)
	Delete(id string) (err error)
	Update(id string, args models.ApmRequest) (err error)
}

type apm struct {
	monitor *Monitor
	region  string
	client  *tapm.Client
}

func newApm(monitor *Monitor, region string) ApmInterface {
	v := &apm{
		monitor: monitor,
		region:  region,
	}
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = string(ApmEndPoint)
	client, _ := tapm.NewClient(v.monitor.Credential(), v.region, cpf)
	v.client = client
	return v
}

// Create 创建APM应用
func (a *apm) Create(args models.ApmRequest) (result models.CreateResponseParams, err error) {
	request := tapm.NewCreateApmInstanceRequest()
	request.Name = common.StringPtr(args.Name)
	request.Description = common.StringPtr(args.Description)
	var days int64
	switch {
	case args.TraceDuration < 1:
		args.TraceDuration = 1
	case args.TraceDuration > 30:
		args.TraceDuration = 30
	default:
		args.TraceDuration = 7
	}
	days = args.TraceDuration * 86400
	request.TraceDuration = common.Int64Ptr(days)
	var tags []*tapm.ApmTag
	for key, val := range args.Tags {
		tags = append(tags, &tapm.ApmTag{
			Key:   common.StringPtr(key),
			Value: common.StringPtr(val),
		})
	}
	request.Tags = tags
	request.SpanDailyCounters = common.Uint64Ptr(10000000)
	response, err := a.client.CreateApmInstance(request)
	if err != nil {
		return
	}
	res := response.Response
	result.InstanceSet = append(result.InstanceSet, *res.InstanceId)
	result.RequestId = *res.RequestId
	return
}

// DescribeApmAgent 获取APM应用Agent接入信息
func (a *apm) DescribeApmAgent(args models.ApmAgentRequest) (result models.ApmAgentInfo, err error) {
	request := tapm.NewDescribeApmAgentRequest()
	request.InstanceId = common.StringPtr(args.Id)
	request.AgentType = common.StringPtr(args.AgentType)
	request.LanguageEnvironment = common.StringPtr(args.Language)
	request.ReportMethod = common.StringPtr("http")
	response, err := a.client.DescribeApmAgent(request)
	if err != nil {
		return
	}
	agent := response.Response.ApmAgent
	result.AgentDownloadURL = *agent.AgentDownloadURL
	result.PublicCollectorURL = *agent.PublicCollectorURL
	result.Token = *agent.Token
	result.PrivateLinkCollectorURL = *agent.PrivateLinkCollectorURL
	result.CollectorURL = *agent.CollectorURL
	result.InnerCollectorURL = *agent.InnerCollectorURL
	return
}

// Update 更新APM应用配置
func (a *apm) Update(id string, args models.ApmRequest) (err error) {
	request := tapm.NewModifyApmInstanceRequest()
	request.InstanceId = common.StringPtr(id)
	request.Description = common.StringPtr(args.Description)
	var days int64
	switch {
	case args.TraceDuration < 1:
		args.TraceDuration = 1
	case args.TraceDuration > 30:
		args.TraceDuration = 30
	default:
		args.TraceDuration = 7
	}
	days = args.TraceDuration * 86400
	request.TraceDuration = common.Int64Ptr(days)
	request.Name = common.StringPtr(args.Name)
	if args.SpanDailyCounters < 10000000 {
		args.SpanDailyCounters = 10000000
	}
	request.SpanDailyCounters = common.Uint64Ptr(args.SpanDailyCounters)
	request.OpenBilling = common.BoolPtr(true)
	_, err = a.client.ModifyApmInstance(request)
	return
}

// Delete 删除APM应用
func (a *apm) Delete(id string) (err error) {
	request := tapm.NewTerminateApmInstanceRequest()
	request.InstanceId = common.StringPtr(id)
	_, err = a.client.TerminateApmInstance(request)
	return
}

// Get 获取APM应用
func (a *apm) Get(id string) (result models.ApmResponse, err error) {
	list, err := a.query(id, "")
	if len(list) > 0 {
		result = list[0]
	}
	return
}

func (a *apm) ListByName(name string) (list []models.ApmResponse, err error) {
	return a.query("", name)
}

func (a *apm) ListAll() (list []models.ApmResponse, err error) {
	return a.query("", "")
}

func (a *apm) query(id string, name string) (list []models.ApmResponse, err error) {
	request := tapm.NewDescribeApmInstancesRequest()
	if strings.TrimSpace(id) != "" {
		request.InstanceIds = common.StringPtrs([]string{id})
	}
	if strings.TrimSpace(name) != "" {
		request.InstanceName = common.StringPtr(name)
	}
	response, err := a.client.DescribeApmInstances(request)
	if err != nil {
		return
	}
	for _, row := range response.Response.Instances {
		list = append(list, models.ApmResponse{
			AmountOfUsedStorage:       *row.AmountOfUsedStorage,
			Name:                      *row.Name,
			InstanceId:                *row.InstanceId,
			ServiceCount:              *row.ServiceCount,
			CountOfReportSpanPerDay:   *row.CountOfReportSpanPerDay,
			AppId:                     *row.AppId,
			TraceDuration:             *row.TraceDuration,
			Description:               *row.Description,
			Status:                    *row.Status,
			Region:                    *row.Region,
			SpanDailyCounters:         *row.SpanDailyCounters,
			BillingInstance:           *row.BillingInstance,
			ErrRateThreshold:          *row.ErrRateThreshold,
			SampleRate:                *row.SampleRate,
			ErrorSample:               *row.ErrorSample,
			SlowRequestSavedThreshold: *row.SlowRequestSavedThreshold,
			ClientCount:               *row.ClientCount,
			TotalCount:                *row.TotalCount,
			MetricDuration:            *row.MetricDuration,
		})
	}
	return
}
